﻿using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.DirectX.Direct3D;
using Microsoft.DirectX;
using D3D = Microsoft.DirectX.Direct3D;
using System.Drawing;

namespace DX1
{
    public class MyObject
    {
        public Mesh m;                 //Mesh - klasa siatki obiektu
        public Device dev;
        public ExtendedMaterial[] ExtendedMaterials;   // Tablica ExtendedMateriałów obiektu, z której wydobędziemy
        public Texture[] Textures;                     // tekstury
        public Material[] Materials;                   // i materiały
        public Vector3 center, BoxMin, BoxMax;          // center, radius - sfera otaczająca
        public float radius;                            // BoxMin,BoxMax - box otaczający

        public CustomVertex.PositionNormalTextured[] vertices;
        public int NoV;

        public MyObject(ref Device d)             // prosty konstruktor
        {
            m = null;
            dev = d;
        }

        public void Render()                // Rendering obiektu na device
        {
            dev.VertexFormat = m.VertexFormat;   //Ustalamy Format Vertexów

            for (int i = 0; i < ExtendedMaterials.Length; i++)      //EM.Length zawiera liczbę submeshów danego mesha
            {
                dev.Material = Materials[i];            //każdy submesh ma inny materiał
                dev.SetTexture(0, Textures[i]);         //i inną teksturę
                m.DrawSubset(i);                        //rendering i-tego submesha
            }
        }


        public void RenderPoints()
        {
            dev.VertexFormat = m.VertexFormat;

            dev.DrawUserPrimitives(D3D.PrimitiveType.PointList,
                               NoV,
                               vertices);
        }

        public float DegreeToRadian(float angle)
        {
            return (float)Math.PI * angle / 180.0f;
        }

        public void CreateTerrainFromFile(float StepX, float StepY, float StepZ, string Filename)
        {
            Bitmap b = new Bitmap(Filename);

            int NoX = b.Size.Width;
            int NoZ = b.Size.Height;
            int NoV = NoX * NoZ;
            int NoF = (NoX - 1) * (NoZ - 1) * 2 * 3;

            CustomVertex.PositionNormalTextured[] vertices = new CustomVertex.PositionNormalTextured[NoV];

            int k = 0;
            for (int i = 0; i < NoX; i++)
                for (int j = 0; j < NoZ; j++)
                {
                    vertices[k].Position = new Vector3(i * StepX - (NoX / 2) * StepX, b.GetPixel(i, j).R * StepZ, j * StepY - (NoZ / 2) * StepY);
                    vertices[k].Tu = i / (float)(NoX - 1);
                    vertices[k].Tv = j / (float)(NoZ - 1);
                    vertices[k].Normal = new Vector3(0, 0, 0);
                    k++;
                }
            int[] indices = new int[NoF];

            k = 0;
            for (int i = 1; i < NoX; i++)
                for (int j = 1; j < NoZ; j++)
                {
                    indices[k++] = i * NoZ + j - 1;
                    indices[k++] = (i - 1) * NoZ + j - 1;
                    indices[k++] = (i - 1) * NoZ + j;

                    indices[k++] = i * NoZ + j;
                    indices[k++] = i * NoZ + j - 1;
                    indices[k++] = (i - 1) * NoZ + j;


                }

            m = new Mesh(NoF, NoV, MeshFlags.Managed | MeshFlags.Use32Bit, CustomVertex.PositionNormalTextured.Format, dev);


            m.IndexBuffer.SetData(indices, 0, LockFlags.None);
            m.VertexBuffer.SetData(vertices, 0, LockFlags.None);
            //m.ComputeNormals();
            CalculateBounds();
            ExtendedMaterials = new ExtendedMaterial[1];
            Textures = new Texture[1];
            Materials = new Material[1];
            ExtendedMaterials[0] = new ExtendedMaterial();
            Textures[0] = null;
            Materials[0] = new Material();
            Materials[0].Ambient = Color.White;
            Materials[0].Diffuse = Color.White;


        }

        public void LoadTexture(int Nr, string FileName)
        {
            if ((Textures != null) && (Textures.Length > Nr))
                Textures[Nr] = TextureLoader.FromFile(dev, FileName);
        }

        public void CalculateBounds()
        {
            VertexBuffer vertices = m.VertexBuffer;  // za pomocą klasy Geometry liczymy Bounding Box i Bounding Sphere
            GraphicsStream stream = vertices.Lock(0, 0, LockFlags.None);
            radius = Geometry.ComputeBoundingSphere(stream, m.NumberVertices, m.VertexFormat, out center);
            Geometry.ComputeBoundingBox(stream, m.NumberVertices, m.VertexFormat, out BoxMin, out BoxMax);
            vertices.Unlock();
        }


        public void LoadFromFile(string FileName)
        {
            m = Mesh.FromFile(FileName, MeshFlags.Managed, dev, out ExtendedMaterials); //Tu wczytujemy plik .x

            CalculateBounds();

            if ((ExtendedMaterials != null) && (ExtendedMaterials.Length > 0))      // Dla każdego Submesha tworzymy materiał i 
            {                                                                       // wczytujemy właściwą teksturę
                Textures = new Texture[ExtendedMaterials.Length];
                Materials = new Material[ExtendedMaterials.Length];
                for (int i = 0; i < ExtendedMaterials.Length; i++)
                {
                    Materials[i] = ExtendedMaterials[i].Material3D;
                    Materials[i].Ambient = Materials[i].Diffuse;
                    if ((ExtendedMaterials[i].TextureFilename != null) && (ExtendedMaterials[i].TextureFilename != string.Empty))
                    {
                        Textures[i] = TextureLoader.FromFile(dev, ExtendedMaterials[i].TextureFilename);
                    }
                }
            }
        }
    }
}
